package com.seleniti.enpareja.web.desktop.server;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpSession;

import org.ioc.commons.impl.gwt.integration.server.service.japtsy.servlet.JAPTSYServiceServlet_JDOImpl;
import org.ioc.commons.japtsy.server.model.biz.InvocationResult;

import com.seleniti.enpareja.controller.common.domain.LoggedUserInfo;
import com.seleniti.enpareja.web.desktop.server.model.integration.service.impl.appengine.GAEService;

public class EnParejaJAPTSYServlet extends JAPTSYServiceServlet_JDOImpl {

	private static final String LOGGED_USER_INFO_ATTRIBUTE_NAME = "loggedUserInfo";

	/**
	 * Serial no.
	 */
	private static final long serialVersionUID = 5713259647256465605L;

	private final ThreadLocal<Map<Class<?>, Object>> cachedServices = new ThreadLocal<Map<Class<?>, Object>>();

	private PersistenceManagerFactory PMF;

	@Override
	public void init() throws ServletException {
		super.init();

		this.setGetObjectByIdValidateParameter(true);

		PMF = JDOHelper.getPersistenceManagerFactory("transactions-optional");
	}

	private final ThreadLocal<PersistenceManager> pmPerThread = new ThreadLocal<PersistenceManager>();

	@Override
	public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException {
		PersistenceManager persistenceManager = null;
		try {
			persistenceManager = PMF.getPersistenceManager();
			pmPerThread.set(persistenceManager);
			super.service(req, resp);
			pmPerThread.set(null);
		} finally {
			if (persistenceManager != null) {
				persistenceManager.close();
			}
		}
	}

	@Override
	protected PersistenceManager getPersistenceManager() {

		return pmPerThread.get();
	}

	@Override
	protected synchronized Object getServiceInstance(Class<?> serviceClass) throws InstantiationException,
			IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException,
			SecurityException {

		if (cachedServices.get() == null) {
			cachedServices.set(new HashMap<Class<?>, Object>());
		}

		Object serviceInstance = cachedServices.get().get(serviceClass);
		if (serviceInstance == null) {
			serviceInstance = serviceClass.newInstance();
			cachedServices.get().put(serviceClass, serviceInstance);
		}

		((GAEService) serviceInstance).setPersistentManager(getPersistenceManager());

		return serviceInstance;
	}

	@Override
	protected InvocationResult invoke(Object serviceInstance, Method method, Object... args)
			throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, Exception {
		HttpSession session = this.perThreadRequest.get().getSession();

		LoggedUserInfo loggedUserInfo = (LoggedUserInfo) session.getAttribute(LOGGED_USER_INFO_ATTRIBUTE_NAME);
		((GAEService) serviceInstance).setSessionLoggedUserInfo(loggedUserInfo);

		InvocationResult result = super.invoke(serviceInstance, method, args);

		loggedUserInfo = ((GAEService) serviceInstance).getSessionLoggedUserInfo();

		if (loggedUserInfo != null) {
			loggedUserInfo.setSessionId(session.getId());
		}

		session.setAttribute(LOGGED_USER_INFO_ATTRIBUTE_NAME, loggedUserInfo);

		return result;
	}

	@Override
	protected void checkPermutationStrongName() throws SecurityException {
		/*
		 * Overridden to avoid exception when call comes from Android
		 */
		// super.checkPermutationStrongName();
	}

}
